﻿//****************************************************************************
//
//  File:       Ribbon.cs
//
//  Contents:   singleton class that is used as a façade for the Windows 
//              Ribbon Framework. In charge of initialization and 
//              communication with the Windows Ribbon Framework.
//
//****************************************************************************

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using MS.WindowsAPICodePack.Internal;
using RibbonLib.Interop;

namespace RibbonLib
{
	/// <summary>
	/// IRibbonForm interface should be implemented by the main form who want the ribbon
	/// </summary>
	public interface IRibbonForm : IUICommandHandler
	{
		/// <summary>
		/// Getter for the main form window handle
		/// </summary>
		IntPtr WindowHandle { get; }

		/// <summary>
		/// Called when the ribbon height is changed, 
		/// allowing the form to reposition its controls so the ribbon doesn't hide them.
		/// </summary>
		/// <param name="newHeight">new height</param>
		void RibbonHeightUpdated(int newHeight);
	}

	[ComVisible(true)]
	[Guid("B13C3248-093D-4366-9832-A936610846FD")]
	internal class RibbonUIApplication : IUIApplication
	{
		IUIRibbon _ribbon;                 // Ribbon
		IRibbonForm ribbonForm;

		public RibbonUIApplication(IRibbonForm form)
		{
			ribbonForm = form;
		}

		#region IUIApplication Members

		public HRESULT OnViewChanged(uint viewId, UI_ViewType typeID, object view, UI_ViewVerb verb, int uReasonCode)
		{
			HRESULT hr = HRESULT.E_FAIL;

			// Checks to see if the view that was changed was a Ribbon view.
			if (typeID == UI_ViewType.Ribbon)
			{
				switch (verb)
				{
					// The view was newly created
					case UI_ViewVerb.Create:
						if (_ribbon == null)
						{
							_ribbon = view as IUIRibbon;
						}
						hr = HRESULT.S_OK;
						break;

					// The view has been resized.  For the Ribbon view, the application should
					// call GetHeight to determine the height of the ribbon.
					case UI_ViewVerb.Size:
						uint uRibbonHeight;
						// Call to the framework to determine the desired height of the Ribbon.
						hr = _ribbon.GetHeight(out uRibbonHeight);

						if (CoreErrorHelper.Failed(hr))
						{
							// error
						}
						else
						{
							ribbonForm.RibbonHeightUpdated((int)uRibbonHeight);
						}
						break;

					// The view was destroyed.
					case UI_ViewVerb.Destroy:

						_ribbon = null;
						hr = HRESULT.S_OK;
						break;

					default:
						break;

				}

			}

			return hr;
		}

		public HRESULT OnCreateUICommand(uint commandId, UI_CommandType typeID, out IUICommandHandler commandHandler)
		{
			// commandHandler = this.commandHandler as IUICommandHandler;
			commandHandler = this.ribbonForm as IUICommandHandler;
			return HRESULT.S_OK;
		}

		public HRESULT OnDestroyUICommand(uint commandId, UI_CommandType typeID, IUICommandHandler commandHandler)
		{
			return HRESULT.E_FAIL;
		}

		#endregion
	}


	public class Ribbon
	{

		private static Ribbon instance;

		private Ribbon()
		{
		}

		public static Ribbon Instance
		{
			get
			{
				if (instance == null)
				{
					instance = new Ribbon();
				}
				return instance;
			}
		}

		private IUIFramework framework;

		public IUIFramework Framework
		{
			get
			{
				return framework;
			}
		}

		private IUIApplication app;

		private IUIFramework CreateRibbonFramework()
		{
			return new UIRibbonFramework() as IUIFramework;
		}

		public void InitFramework(IRibbonForm form)
		{
			InitFramework(form, "APPLICATION_RIBBON", Assembly.GetEntryAssembly().GetModules()[0]);
		}

		public void InitFramework(IRibbonForm form, string resourceName, Module resourceModule)
		{
			HRESULT hr;

			// create ribbon framework object
			framework = CreateRibbonFramework();

			// create ribbon application object
			app = new RibbonUIApplication(form);

			// init ribbon framework
			hr = framework.Initialize(form.WindowHandle, app);
			if (CoreErrorHelper.Failed(hr))
			{
				Marshal.ThrowExceptionForHR((int)hr);
			}

			// get main module HINSTANCE
			IntPtr instance = Marshal.GetHINSTANCE(resourceModule);

			// load UI from ribbon markup
			framework.LoadUI(instance, resourceName);
		}

		public void InitFramework(IRibbonForm form, string resourceName, IntPtr hInstance)
		{
			HRESULT hr;

			// create ribbon framework object
			framework = CreateRibbonFramework();

			// create ribbon application object
			app = new RibbonUIApplication(form);

			// init ribbon framework
			hr = framework.Initialize(form.WindowHandle, app);
			if (CoreErrorHelper.Failed(hr))
			{
				Marshal.ThrowExceptionForHR((int)hr);
			}

			// load UI from ribbon markup
			HRESULT x = framework.LoadUI(hInstance, resourceName);
		}

		public void DestroyFramework()
		{
			if (framework != null)
			{
				// destroy ribbon framework
				framework.Destroy();
				Marshal.ReleaseComObject(framework);
				framework = null;
			}

			if (app != null)
			{
				app = null;
			}
		}
	}
}
